package jmine.tec.web.wicket.pages.validator;

import static jmine.tec.web.wicket.WebWicketMessages.DATE_FIELD_GREATER_THAN_COMPARISON;
import static jmine.tec.web.wicket.WebWicketMessages.DATE_SPAN_IN_DAYS_GREATER_THAN_EXPECTED;
import static jmine.tec.web.wicket.WebWicketMessages.FORM_COMPONENT_IS_REQUIRED;
import static jmine.tec.web.wicket.WebWicketMessages.FORM_LABEL_END_DATE;
import static jmine.tec.web.wicket.WebWicketMessages.FORM_LABEL_START_DATE;

import java.util.Date;

import jmine.tec.utils.date.DatePeriod;

import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.FormComponent;

/**
 * Validates if the date interval is within the allowed value.
 * Both form components must be required.  
 * 
 * @author seiti
 * Jun 20, 2012
 */
public class DateIntervalFormValidator extends AbstractFormValidator {

    private FormComponent<Date>[] components;

    private int maxDateSpanInDays;

    /**
     * Ctor
     * 
     * @param start start
     * @param end end
     * @param maxDateSpan interval
     */
    public DateIntervalFormValidator(FormComponent<Date> start, FormComponent<Date> end, Interval maxDateSpan) {
        this(start, end, maxDateSpan.getDays());
    }
    
    /**
     * Ctor
     * 
     * @param start start
     * @param end end
     * @param maxDaysInterval maximum number of days allowed 
     */
    @SuppressWarnings("unchecked")
    public DateIntervalFormValidator(FormComponent<Date> start, FormComponent<Date> end, int maxDaysInterval) {
        if (start == null) {
            throw new IllegalArgumentException("argument inicio cannot be null");
        }
        if (end == null) {
            throw new IllegalArgumentException("argument fim cannot be null");
        }
        this.components = new FormComponent[]{ start, end };
        this.maxDateSpanInDays = maxDaysInterval;
    }

    /**
     * {@inheritDoc}
     */
    public FormComponent<?>[] getDependentFormComponents() {
        return components;
    }

    /**
     * {@inheritDoc}
     */
    public void validate(Form<?> form) {

        final FormComponent<Date> startComponent = this.components[0];
        final FormComponent<Date> endComponent = this.components[1];

        Date start = startComponent.getConvertedInput();
        Date end = endComponent.getConvertedInput();

        if (start == null) { 
            this.error(startComponent, FORM_COMPONENT_IS_REQUIRED.create(startComponent.getLabel().getObject()));
        }
    
        if (end == null) {
            this.error(startComponent, FORM_COMPONENT_IS_REQUIRED.create(endComponent.getLabel().getObject()));
        }   
        
        if (start.after(end)) {
            String startLabel = startComponent.getLabel() != null ? startComponent.getLabel().getObject() : FORM_LABEL_START_DATE.create().getMessage();
            String endLabel = endComponent.getLabel() != null ? endComponent.getLabel().getObject() : FORM_LABEL_END_DATE.create().getMessage();
            this.error(startComponent, DATE_FIELD_GREATER_THAN_COMPARISON.create(endLabel, end, startLabel, start));
        }

        int dateSpanInDays = DatePeriod.difference(start, end).days();
        if (dateSpanInDays > maxDateSpanInDays) {
            this.error(startComponent, DATE_SPAN_IN_DAYS_GREATER_THAN_EXPECTED.create(start, end, dateSpanInDays, maxDateSpanInDays));
         }
    }

    /**
     * Mostly used values should be in this enum.  
     */
    public enum Interval {
        WEEK(7),
        MONTH(30);
        
        private int days;
        
        /**
         * Ctor 
         * 
         * @param days days
         */
        private Interval(int days) {
            this.days = days;
        }
        
        /**
         * @return number of days
         */
        public int getDays() {
            return this.days;
        }
    }
}
